Multiple Inheritance(다중 상속)Java와 달리 C++은 다중 상속을 허용한다.
복수의 부모 클래스서브 클래스의 멤버는 모든 슈퍼 클래스 멤버의 조합이다.
class student{
virtual void all_info(void) const {
cout<<"[student] My name is "<<name<<endl;
cout<<" I passed the follwing grades: "<<passed<<endl;
}
};
class mathematician{
virtual void all_info(void) const {
cout<<"[mathman] My name is "<<name<<endl;
cout<<" I proved: "<<proved<<endl;
}
};
class math_student: public student, public mathematician{
};
int main(void){
math_student bob("Robert Robson", "Algebra", "Fermat's Last Therom");
bob.all_info();
}
위와 같이 공통된 서명을 가지는 가상 함수를 갖고 있는 클래스를 다중 상속한 경우,
해당 상속의 우선순위가 존재하지 않는다.(모호함)
위와 같은 모호함을 없애주기 위해서는 클래스에서 멤버 함수를 적절하게 정의해 주어야 한다.
하나 이상의 슈퍼 클래스를 private나 protected로 상속할 경우 멤버 함수의 모호함을 제거할 수 있다.
class student{ };
class mathematician{ };
class math_student: public student, private mathmatician{
};
하지만, 외부에서 더 이상 mathmatician::all_info() 함수에 접근할 수 없다.
중복성과 모호함
class person{ };
class student{ };
class mathmatician: public person{
public:
mathmatician(const string& name, const string& proved): person(name), proved(proved) {}
virtual void all_info(void) const override {
person::all_info();
cout<<" I proved: "<<proved<<endl;
}
private:
string proved;
};
class math_student: public student, public mathmatician{
public:
math_student(const string& name, const string& passed, const string& proved): student(name, passed), mathmatician(name, proved) {}
virtual void all_info(void) const override {
student::all_info();
mathmatician::all_info();
}
};
int main(void){
math_student bob("Robert Robson", "Algebra", "Fermat's Last Theorem");
bob.all_info();
}
두개를 상속받은 클래스에서 해당 virtual 함수를 override 하였기 때문에 문제 없이 동작한다.
- 중복성: name 변수가 두번 저장된다.(student, mathematician의 name 변수가 따로 존재함)
- 오류가 발생하기 쉬움(두 변수의 값이 일치함을 보장할 수 없다.)
- 모호함: math_student에서 person::name에 접근할 때, 모호함
class math_student: public student, public mathmatician{
public:
math_student(const string& name, const string& passed, const string& proved): student(name, passed), mathmatician(name, proved) {}
virtual void all_info(void) const override {
person::all_info();
}
};
math_student에서 슈퍼 클래스의 all_info()를 호출했을 경우,
student의 person::all_info()와 mathmatician의 person::all_info() 사이에 모호함이 발생한다.
가상 베이스 클래스(Virtual Base Class)가상 베이스 클래스를 사용하면, 공통 슈퍼 클래스에 멤버를 한번만 저장한다.
(위의 문제점들 해결 가능)
class person{ };
class student: public virtual person{
};
class mathematician: public virtual person{
};
class math_student: public student, public mathmatician{
public:
math_student(const string& name, const string& passed, const string& proved): student(name, passed), mathematician(name, passed) {}
};
math_student에서 student와 mathematician에 대하여 생성자를 호출하였지만,
모호함에 대한 에러가 출력되지 않는다.
내부적으로 virtual 베이스 클래스가 가지는 변수들이 분리되어 있다.
student와 mathematician은 내부에서 포인터(vbase)를 통해 공통된 base_class를 가르킨다.
가상 기본 클래스의 경우, 공유 기본 클래스 생성자를 호출하는 동작은 가장 나중에 파생된 클래스의 책임으로
전가한다.
위에서 mathematician과 student에서 person 생성자를 호출하는 동작은 파생 클래스에서 간접적으로 호출될 때,
비화성화 됨
class student: public virtual person{
protected:
student(const string& passed): passed(passed) {}
};
class mathematician: public virtual person{
protected:
mathematician(const string& proved): proved(proved) {}
};
class math_student: public student, public mathmatician{
public:
math_student(const string& name, const string& passed, const string& proved): person(name), student(passed), mathematician(proved) {}
virtual void all_info(void) const override{
student::all_info();
mathematician::my_infos();
}
}
위와 같이 math_student에서 person(베이스 클래스)에 대한 생성자를 따로 호출하는 것이 좋다.
포괄적인 처리는 person의 멤버함수인 2개의 인수를 갖는 생성자와 all_info를 통합한다.
배타적인 처리는 클래스 자체의 멤버로만 처리한다.(protected)
- privated: 클래스 내에서만 접근할 수 있는 데이터 멤버
- protected: 자신의 개체에 사용되지 않는 서브 클래스에 필요한 멤버 함수
- public: 클래스 개체를 대상으로 하는 멤버 함수